﻿#include "MkLog.h"
#include "MkGlobal.h"
#include <stdarg.h>


#define MAX_LOG_SIZE   1500

CMkLog CMkLog::m_Instance;
CMkLog::CMkLog() :m_LogQueue(1000)
{
    m_strLogPath.clear();
    m_strModuleName.clear();
    m_bInited = FALSE;
    m_WriteLevel = LOG_ERROR;
    m_WriteDst = TO_SCREEN;
}

CMkLog::~CMkLog()
{
    m_strLogPath.clear();
    m_strModuleName.clear();
    m_bInited = FALSE;
    m_WriteLevel = LOG_ERROR;
    m_WriteDst = TO_SCREEN;
}

Uint32 CMkLog::Initialize(const MkString& strLogPath, const MkString& strModuleName, Uint32 dst/* = TO_SCREEN*/)
{
    m_strModuleName = strModuleName;
    m_WriteDst = dst;

    if (TO_FILE & dst)
    {
        m_strLogPath = strLogPath;
        if (NoneError != GetStorePath(strLogPath, m_strStorePath))
        {
            printf("get store path failed\n");
            return InitLogFailed;
        }
        if (!CheckFileIsExist(strLogPath.c_str()))
        {
            if (NoneError != MakeDir(strLogPath.c_str()))
            {
                printf("mkdir logpath failed\n");
                return SetLogPathFailed;
            }
        }
        if (!CheckDirIsExist(m_strStorePath.c_str()))
        {
            if (NoneError != MakeDir(m_strStorePath.c_str()))
            {
                printf("create storepath failed\n");
                return CreateFolderFailed;
            }
        }
    }
    m_bInited = TRUE;
    return m_LogThread.Start(LogThread, this);
}

void CMkLog::Release()
{
    m_bInited = FALSE;
    m_LogQueue.Input("111");
    m_LogThread.Stop();
    m_LogQueue.Clear();
}

Uint32 CMkLog::GetStorePath(const MkString& LogPath, OUT MkString& StorePath)
{
    int iPos = LogPath.rfind('/');
    if (-1 == iPos)
    {
        iPos = LogPath.rfind('\\');
    }

    if (-1 == iPos)
    {
        return UnknownError;
    }

    StorePath = LogPath.substr(0, iPos + 1) + "log_store";

    return NoneError;
}

Uint32 CMkLog::ChangeWriteLevel(LOG_LEVEL Level)
{
    m_WriteLevel = Level;
    return NoneError;
}

Uint32 CMkLog::GetWriteLevel(OUT LOG_LEVEL& Level)
{
    Level = m_WriteLevel;
    return NoneError;
}

Uint32 CMkLog::ChangeWriteDst(Uint32 Dst)
{
    m_WriteDst = Dst;
    return NoneError;
}

Uint32 CMkLog::GetWriteDst(OUT Uint32& Dst)
{
    Dst = m_WriteDst;
    return NoneError;
}

Uint32 CMkLog::GetModuleName(OUT MkString& strModuleName)
{
    strModuleName = m_strModuleName;
    return NoneError;
}

Uint32 CMkLog::GetstrLevel(LOG_LEVEL Level, OUT MkString& strLevel)
{
    switch (Level)
    {
    case LOG_INFO:
        strLevel = "INFO";
        break;
    case LOG_DEBUG:
        strLevel = "DEBUG";
        break;
    case LOG_WARNING:
        strLevel = "WARN";
        break;
    case LOG_ERROR:
        strLevel = "ERROR";
        break;
    default:
        strLevel = "";
        break;
    }
    return NoneError;
}
Uint32 CMkLog::GetSimpleFileName(const MkString& SoureFile, MkString& SimpleFile)
{
	size_t FindIndex =  SoureFile.rfind("/");
	if (-1 == FindIndex)
	{
		FindIndex = SoureFile.rfind("\\");
	}
	FindIndex += 1;
	SimpleFile = SoureFile.substr(FindIndex);
	return NoneError;
}

Uint32 CMkLog::WriteLog(LOG_LEVEL Level, const char* FileName, int Line, const char* format, ...)
{
    if (FALSE == m_bInited)
    {
        printf("log is not init\n");
        return WriteLogFailed;
    }
    if (Level >= m_WriteLevel)
    {
        char buffer[MAX_LOG_SIZE] = { 0 };
        MkString strTime;
        MkString strLevel;
		MkString SimpleFileName;
        Uint32 bufLen = 0;

        if (NoneError != GetstrTime(strTime))
        {
            return WriteLogFailed;
        }
        GetstrLevel(Level, strLevel);
		GetSimpleFileName(FileName, SimpleFileName);
        snprintf(buffer, MAX_LOG_SIZE, "%s [%s] %s:%d: ", strTime.c_str(), strLevel.c_str(), SimpleFileName.c_str(), Line);
        //snprintf(buffer, MAX_MSG_LEN, "%s:", strLevel.c_str());
        bufLen = strlen(buffer);

        va_list arg_ptr;
        va_start(arg_ptr, format);
        //_vnsprintf(buffer, format, arg_ptr);
        vsnprintf(buffer + bufLen, MAX_LOG_SIZE - bufLen, format, arg_ptr);
        va_end(arg_ptr);
        buffer[MAX_LOG_SIZE - 1] = '\0';
        m_LogQueue.Input(buffer);
    }
    return NoneError;
}

void CMkLog::LogThread(void* lParam)
{
    CMkLog* pLog = (CMkLog*)lParam;
    if (pLog)
    {
        pLog->DoLog();
    }
}

void CMkLog::DoLog()
{
    //printf("log thread id:%lu\n", GetLocalThreadId());
    MkString strBuffer;
	FILE *fp = NULL;
	MkString strDayTime;
	MkString strTmpDayTime;
	GetLogstrTime(strDayTime);
	MkString LogFile;
    while (m_bInited)
    {
        m_LogQueue.Output(strBuffer, 0xFFFFFFFF);
        if (TO_SCREEN & m_WriteDst)
        {
            printf("%s", strBuffer.c_str());
        }
        if (TO_FILE & m_WriteDst)
        {
			LogFile = m_strLogPath + "/" + m_strModuleName + "_" + strDayTime + ".log";
			fp = fopen(LogFile.c_str(), "a+");
			if (NULL != fp)
			{
				fwrite(strBuffer.c_str(), 1, strBuffer.size(), fp);
				fclose(fp);
			}

//			GetLogstrTime(strTmpDayTime);
//			if (strDayTime != strTmpDayTime)
//			{
//				fclose(fp);
//#ifdef _WIN32
//				MkString strStoreName = m_strStorePath + "/" + m_strModuleName + "_" + strDayTime + ".rar";
//#else
//				MkString strStoreName = m_strStorePath + "/" + m_strModuleName + "_" + strDayTime + ".tar.bz2";
//#endif
//				BackUpFile(LogFile.c_str(), strStoreName.c_str());
//				DeleteLocalFile(LogFile.c_str());
//				strDayTime = strTmpDayTime;
//				LogFile = m_strLogPath + "/" + m_strModuleName + "_" + strDayTime + ".log";
//				fp = fopen(LogFile.c_str(), "a+");
//			}
        }
    }
}
